﻿// Fill out your copyright notice in the Description page of Project Settings.

#include "gameLiftActor.h"
#include "GameLiftModel.h"
#include "Engine/StaticMesh.h"
//#include "StaticMeshResources.h"
//#include "GeomTools.h"
//#include "RawIndexBuffer.h"

void FPricedMeshData::Clear()
{
	Triangles.Reset();
	Vertices.Reset();
	Normals.Reset();
	UV0.Reset();
	VertexColors.Reset();
	MeshTangent.Reset();
}


bool FPricedMeshData::IsValid()const 
{
	return Vertices.Num() >= 3 && Triangles.Num() >= 3;
}

AGameLiftActor::AGameLiftActor():
	liftWorld(nullptr)
{

	proceduralMeshComponent =  CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("liftComponent"));
	RootComponent = proceduralMeshComponent;
	proceduralMeshComponent->bGenerateOverlapEvents = false;
}

AGameLiftActor::~AGameLiftActor() 
{
	if (liftWorld) 
	{
		delete liftWorld;
		GLog->Log("		delete liftWorld;");
	}

}



void AGameLiftActor::InitWorld(int x, int y, int z)
{
	liftWorld = new FLiftWorld();
	needTick = false;
	if (liftWorld->InitWorld(x, y, z)) 
	{

	}

}

void AGameLiftActor::InitStage(UStaticMesh* mesh)
{	

	if (CopyMeshData(mesh)&& liftWorld) 
	{
		proceduralMeshComponent->ClearAllMeshSections();
		ShowMeshData.Clear();
		//FIntVector p;
		//for (uint32 i = 0; i < liftWorld->GetAllNode(); i++) 
		//{
		//	//FIntVector p = FIntVector(0, i, 0);
		//	p = liftWorld->GetNodeC(i)->GetPoint();
		//	AddOneNodeToMesh(referMeshData, FVector(p.X*boxSize, p.Y*boxSize, p.Z*boxSize),4);
		//}

		//proceduralMeshComponent->CreateMeshSection(0, ShowMeshData.Vertices, ShowMeshData.Triangles
		//	, ShowMeshData.Normals, ShowMeshData.UV0, ShowMeshData.VertexColors, ShowMeshData.MeshTangent, false);
	}
}

void AGameLiftActor::InitLift(TArray<int> lift)
{
	needTick = false;
	if (liftWorld) 
	{
		liftWorld->SetLiftStart(lift);
	}
}

int AGameLiftActor::UpDataLift()
{
	if (liftWorld&&referMeshData.IsValid())
	{
		liftWorld->UpDataWorld();

		proceduralMeshComponent->ClearAllMeshSections();
		ShowMeshData.Clear();
		const FOneNodeBase* node = nullptr;
		FIntVector p;
		uint8 l;
		for (uint32 i = 0; i < liftWorld->GetAllNode(); i++)
		{
			node = liftWorld->GetNodeC(i);
			//FIntVector p = FIntVector(0, i, 0);
			p = node->GetPoint();
			l = node->GetLift();
			if (l == 1) 
			{
				AddOneNodeToMesh(referMeshData, FVector(p.X*boxSize, p.Y*boxSize, p.Z*boxSize), boxSize);
			}
			//AddOneNodeToMesh(referMeshData, FVector(p.X*boxSize, p.Y*boxSize, p.Z*boxSize), ?9:0.1);
		}

		proceduralMeshComponent->CreateMeshSection(0, ShowMeshData.Vertices, ShowMeshData.Triangles
			, ShowMeshData.Normals, ShowMeshData.UV0, ShowMeshData.VertexColors, ShowMeshData.MeshTangent, false);

		return liftWorld->GetLiveTime();

	}

	return -1;
}


int AGameLiftActor::ChangeTickTyp()
{
	if (needTick) 
	{
		needTick = false;
	
	}
	else 
	{
		if (UpDataLift()>=0)
		{
			needTick = true;
		}
	}
	return needTick;
}

void AGameLiftActor::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	if (needTick)
	{
		UpDataLift();
	}

}




void AGameLiftActor::AddOneNodeToMesh(const FPricedMeshData& node, FVector point,float size) 
{
	int start = ShowMeshData.Vertices.Num();
	
	
	for (int i = 0; i < node.Vertices.Num(); i++) 
	{
		ShowMeshData.Vertices.Emplace(node.Vertices[i]* size + point);
	}

	for (int i = 0; i < node.Triangles.Num(); i++)
	{
		ShowMeshData.Triangles.Emplace(node.Triangles[i] + start);
	}

	ShowMeshData.Normals.Append(node.Normals);
	ShowMeshData.UV0.Append(node.UV0);
	ShowMeshData.MeshTangent.Append(node.MeshTangent);
	ShowMeshData.VertexColors.Append(node.VertexColors);

}

void  AGameLiftActor::SetKeepKey(int minKeep, int maxKeep, int maxNear)
{
	FOneNode3D::minKeep = minKeep;
	FOneNode3D::maxKeep = maxKeep;
	FOneNode3D::maxNear = maxNear;
}


void AGameLiftActor::GetKeepKey(int& minKeep, int& maxKeep, int& maxNear)
{
	minKeep = FOneNode3D::minKeep;
	maxKeep = FOneNode3D::maxKeep;
	maxNear = FOneNode3D::maxNear;
}


int32 GetNewIndexForOldVertIndex(int32 MeshVertIndex, TMap<int32, int32>& MeshToSectionVertMap, const FStaticMeshVertexBuffers& VertexBuffers, TArray<FVector>& Vertices, TArray<FVector>& Normals, TArray<FVector2D>& UVs, TArray<FProcMeshTangent>& Tangents)
{
	//return 0;
	int32* NewIndexPtr = MeshToSectionVertMap.Find(MeshVertIndex);
	if (NewIndexPtr != nullptr)
	{
		return *NewIndexPtr;
	}
	else
	{
		// Copy position
		int32 SectionVertIndex = Vertices.Add(VertexBuffers.PositionVertexBuffer.VertexPosition(MeshVertIndex));

		 //Copy normal
		Normals.Add(VertexBuffers.StaticMeshVertexBuffer.VertexTangentZ(MeshVertIndex));
		check(Normals.Num() == Vertices.Num());

		//// Copy UVs
		UVs.Add(VertexBuffers.StaticMeshVertexBuffer.GetVertexUV(MeshVertIndex, 0));
		check(UVs.Num() == Vertices.Num());

		// Copy tangents
		FVector4 TangentX = VertexBuffers.StaticMeshVertexBuffer.VertexTangentX(MeshVertIndex);
		FProcMeshTangent NewTangent(TangentX, TangentX.W < 0.f);
		Tangents.Add(NewTangent);
		check(Tangents.Num() == Vertices.Num());

		MeshToSectionVertMap.Add(MeshVertIndex, SectionVertIndex);

		return SectionVertIndex;
	}
}


bool  AGameLiftActor::CopyMeshData(UStaticMesh* mesh)
{

	if (mesh) 
	{
		referMeshData.Clear();
		bool bAllowCPUAccess = mesh->bAllowCPUAccess;
		mesh->bAllowCPUAccess = true;
		if (mesh->RenderData != nullptr && mesh->RenderData->LODResources.IsValidIndex(0))
		{
			const FStaticMeshLODResources& LOD = mesh->RenderData->LODResources[0];
			if (LOD.Sections.IsValidIndex(0))
			{
				const FStaticMeshSection& Section = LOD.Sections[0];
				const uint32 OnePastLastIndex = Section.FirstIndex + Section.NumTriangles * 3;
				FIndexArrayView Indices = LOD.IndexBuffer.GetArrayView();
				TMap<int32, int32> MeshToSectionVertMap;
				for (uint32 i = Section.FirstIndex; i < OnePastLastIndex; i++)
				{
					uint32 MeshVertIndex = Indices[i];

					// See if we have this vert already in our section vert buffer, and copy vert in if not 
					int32 SectionVertIndex = GetNewIndexForOldVertIndex(MeshVertIndex, MeshToSectionVertMap, LOD.VertexBuffers
						, referMeshData.Vertices, referMeshData.Normals, referMeshData.UV0, referMeshData.MeshTangent);

					// Add to index buffer
					referMeshData.Triangles.Add(SectionVertIndex);
	
				}

				referMeshData.VertexColors.Init(FColor::White, referMeshData.Vertices.Num());
			
			}
			return referMeshData.Vertices.Num() >= 3;
		}

	
		mesh->bAllowCPUAccess = bAllowCPUAccess;


		FBox box = FBox(referMeshData.Vertices);
		FVector center = box.GetCenter();

		for (int i = 0; i < referMeshData.Vertices.Num(); i++) 
		{
			referMeshData.Vertices[i] = referMeshData.Vertices[i] - center;
		}

	}
	return false;

}



